package com.tyk.bookstore.back.platform.service.impl;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tyk.bookstore.back.common.core.util.AssertUtil;
import com.tyk.bookstore.back.common.core.util.ObjUtil;
import com.tyk.bookstore.back.common.core.util.TreeUtil;
import com.tyk.bookstore.back.platform.model.entity.AreaDo;
import com.tyk.bookstore.back.platform.model.entity.CarouselDo;
import com.tyk.bookstore.back.platform.model.query.AreaAddQuery;
import com.tyk.bookstore.back.platform.model.query.AreaListQuery;
import com.tyk.bookstore.back.platform.model.query.AreaPageQuery;
import com.tyk.bookstore.back.platform.model.query.AreaUpdateQuery;
import com.tyk.bookstore.back.platform.model.result.AreaResultEnum;
import com.tyk.bookstore.back.platform.model.vo.AreaListVo;
import com.tyk.bookstore.back.platform.model.vo.AreaPageVo;
import com.tyk.bookstore.back.platform.model.vo.AreaSimVo;
import com.tyk.bookstore.back.platform.model.vo.AreaVo;
import com.tyk.bookstore.back.platform.repository.AreaRepository;
import com.tyk.bookstore.back.platform.service.AreaService;
import com.tyk.bookstore.back.platform.util.MapStructPlatform;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Set;


/**
 * @author tyk
 * @description 行政区域
 */
@Service
@RequiredArgsConstructor

public class AreaServiceImpl extends ServiceImpl<AreaRepository, AreaDo> implements AreaService {

    private final AreaRepository areaRepository;
    private final MapStructPlatform mapStructPlatform;

    @Override
    public List<AreaSimVo> getAreaSimTree() {
        return TreeUtil.buildTree(
                areaRepository.selectList(null),
                AreaDo::getCode,
                AreaDo::getParentCode,
                it -> new AreaSimVo(it.getCode(), it.getName()),
                AreaSimVo::addChild
        );
    }

    @Override
    public List<AreaListVo> getAreaList(AreaListQuery query) {
        LambdaQueryWrapper<AreaDo> w = Wrappers.lambdaQuery(AreaDo.class);
        w.eq(query.getCode() != null, AreaDo::getCode, query.getCode());
        w.eq(query.getParentCode() != null, AreaDo::getParentCode, query.getParentCode());
        w.like(ObjUtil.notBlank(query.getName()), AreaDo::getName, query.getName());
        List<AreaDo> doList = areaRepository.selectList(w);
        return mapStructPlatform.toAreaListVoList(doList);
    }

    @Override
    public AreaVo getById(Long id) {
        AreaDo area = areaRepository.selectById(id);
        return mapStructPlatform.toAreaVo(area, 0);
    }

    @Override
    public AreaPageVo getPage(AreaPageQuery query) {
        Page<AreaDo> page = new Page<>(query.getPage(), query.getLimit());
        LambdaQueryWrapper<AreaDo> w = buildPageWrapper(query);
        areaRepository.selectPage(page, w);
        return mapStructPlatform.toAreaPageVo(page);
    }


    @Override
    public void add(AreaAddQuery query) {

        // 父级存在
        if (!ObjUtil.equal(query.getParentCode(), CarouselDo.TOP_ID))
            AssertUtil.isTrue(
                    areaRepository.exist1Eq(
                            AreaDo::getCode, query.getParentCode(), AreaDo.class
                    ),
                    AreaResultEnum.AREA_PARENT_NOT_FOUND
            );

        // 行政区域不存在
        AssertUtil.isFalse(
                areaRepository.exist1Eq(
                        AreaDo::getCode, query.getCode(), AreaDo.class
                ),
                AreaResultEnum.AREA_ALREADY_EXISTS
        );

        // 添加
        AreaDo area = mapStructPlatform.toAreaDo(query);
        areaRepository.insert(area);
    }

    @Override
    public void updateById(AreaUpdateQuery query) {

        // 行政区域存在
        AssertUtil.isTrue(
                areaRepository.exist1Eq(
                        AreaDo::getCode, query.getCode(), AreaDo.class
                ),
                AreaResultEnum.AREA_ALREADY_EXISTS
        );

        // 父级存在
        if (!ObjUtil.equal(query.getParentCode(), CarouselDo.TOP_ID))
            AssertUtil.isTrue(
                    areaRepository.exist1Eq(
                            AreaDo::getCode, query.getParentCode(), AreaDo.class
                    ),
                    AreaResultEnum.AREA_PARENT_NOT_FOUND
            );

        // 更新
        AreaDo area = mapStructPlatform.toAreaDo(query);
        areaRepository.updateById(area);
    }

    @Override
    public void deleteById(Long code) {
        // 行政区域存在
        AssertUtil.isTrue(
                areaRepository.exist1Eq(
                        AreaDo::getCode, code, AreaDo.class
                ),
                AreaResultEnum.AREA_ALREADY_EXISTS
        );
        // 行政区域不存在下级
        AssertUtil.isFalse(
                areaRepository.exist1Eq(
                        AreaDo::getParentCode, code, AreaDo.class
                ),
                AreaResultEnum.AREA_HAS_CHILD
        );
        // 删除
        areaRepository.deleteById(code);
    }

    @Override
    public void deleteBatchByIdSet(Set<Long> idSet) {
        // 删除
        areaRepository.deleteBatchIds(idSet);
    }

    /**
     * 构建分页查询Wrapper
     *
     * @param query 参数
     * @return Wrapper
     */
    private static LambdaQueryWrapper<AreaDo> buildPageWrapper(AreaPageQuery query) {
        LambdaQueryWrapper<AreaDo> w = new LambdaQueryWrapper<>();
        w.eq(query.getCode() != null, AreaDo::getCode, query.getCode());
        w.eq(query.getParentCode() != null, AreaDo::getParentCode, query.getParentCode());
        w.like(ObjUtil.notBlank(query.getName()), AreaDo::getName, query.getName());
        w.orderBy(true, true, AreaDo::getCode);
        return w;
    }

}

